//
// Created by songpingwang on 25-7-4.
//

#ifndef RE2_H
#define RE2_H


#include <string>
#include <vector>
#include <re2/re2.h>

using std::string;
using std::vector;
using re2::StringPiece;

/**
 * 匹配结果类（模拟Python的Match对象）
 *
 * 基础模板：基于分组数量的分发机制            template <int GROUP_COUNT>FindallImpl
* 特化处理：无分组情况                       template <>struct FindallImpl<0>
* 特化处理：单分组情况                       template <>struct FindallImpl<1>
* 特化处理：多分组情况（GROUP_COUNT >= 2）    template <int GROUP_COUNT>
 */

template <int GROUP_COUNT> struct FindallImpl;

template <>
struct FindallImpl<0> {
    static vector<string> execute(const RE2& pattern, StringPiece input) {
        vector<string> result;
        StringPiece match;
        while (RE2::FindAndConsume(&input, pattern, &match)) {
            result.push_back(string(match));
        }
        return result;
    }
};

template <>
struct FindallImpl<1> {
    static vector<string> execute(const RE2& pattern, StringPiece input) {
        vector<string> result;
        StringPiece group1;
        while (RE2::FindAndConsume(&input, pattern, &group1)) {
            result.push_back(string(group1));
        }
        return result;
    }
};


template <int GROUP_COUNT>
struct FindallImpl {
    static_assert(GROUP_COUNT >= 2, "Only for 2+ groups");
    using ResultType = vector<vector<string>>;
    static ResultType execute(const RE2& pattern, StringPiece input) {
        ResultType result;
        vector<StringPiece> matches(GROUP_COUNT + 1);
        vector<RE2::Arg> argv(GROUP_COUNT + 1);
        vector<RE2::Arg*> args(GROUP_COUNT + 1);

        for (int i = 0; i <= GROUP_COUNT; ++i) {
            argv[i] = RE2::Arg(&matches[i]);
            args[i] = &argv[i];
        }

        while (!input.empty()) {
            if (!RE2::PartialMatchN(input, pattern, args.data(), GROUP_COUNT + 1))
                break;

            vector<string> groups;
            for (int i = 1; i <= GROUP_COUNT; ++i) {
                groups.emplace_back(matches[i]);
            }
            result.push_back(std::move(groups));

            const size_t offset_to_match = matches[0].data() - input.data();
            const size_t advance_amount = offset_to_match + matches[0].size();
            if (advance_amount == 0) {
                if (input.size() > 1) {
                    input.remove_prefix(1);
                    continue;
                }
                break;
            }

            input.remove_prefix(advance_amount);
        }
        return result;
    }
};


/**
 * 匹配函数 用户友好的接口
 *
 * 匹配函数：re2_findall
 * 匹配函数（编译期指定分组数量）：re2_findall_ct
 */
inline auto re2_findall(const RE2& pattern, const string& text) {
    constexpr int group_count = [&pattern]{
        const int g = pattern.NumberOfCapturingGroups();
        return g > 1 ? 2 : g;
    }();

    const StringPiece input(text);
    if constexpr (group_count == 0) {
        return FindallImpl<0>::execute(pattern, input);
    } else if constexpr (group_count == 1) {
        return FindallImpl<1>::execute(pattern, input);
    } else {
        return FindallImpl<2>::execute(pattern, input);
    }
}

/**
 * 匹配函数（编译期指定分组数量）
 *
 * 匹配函数：re2_findall_ct
 */
template <int GROUP_COUNT>
auto re2_findall_ct(const RE2& pattern, const string& text) {
    static_assert(GROUP_COUNT >= 0, "Invalid group count");
    return FindallImpl<GROUP_COUNT>::execute(pattern, text);
}

/*
* int main() {
    // 编译正则表达式
    const RE2 single_group(R"((\d{4})-(\d{2})-(\d{2}))"); // 3分组
    const RE2 no_group(R"(\d+)");
    const string text = "2023-01-15, 2024-02-20, 2025-03-25";

    // 自动选择分组类型
    auto all_dates = re2_findall(single_group, text);
    // 返回 vector<vector<string>>: {{"2023","01","15"}, {"2024","02","20"}, ...}

    auto all_numbers = re2_findall(no_group, text);
    // 返回 vector<string>: {"2023","01","15","2024",...}

    // 编译期指定分组类型（高级用法）
    auto explicit_result = re2_findall_ct<3>(single_group, text);

    return 0;
}
 */


#include <vector>
#include <optional>
#include <string>
#include <stdexcept>
#include <re2/re2.h>
#include <cstddef> // size_t

// 匹配结果类（模拟Python的Match对象）
class MatchObject {
    bool success_;
    std::string full_match_;
    std::vector<std::optional<std::string>> groups_;
    std::vector<std::pair<size_t, size_t>> spans_;

public:
    // 默认构造表示匹配失败
    MatchObject() : success_(false) {}

    // 成功匹配的构造函数
    MatchObject(std::string full_match,
               std::vector<std::optional<std::string>> groups,
               std::vector<std::pair<size_t, size_t>> spans)
        : success_(true), full_match_(std::move(full_match)),
          groups_(std::move(groups)), spans_(std::move(spans)) {}

    explicit operator bool() const { return success_; }

    // 获取分组内容
    std::string group(const int group_id = 0) const {
        if (group_id < 0 || static_cast<size_t>(group_id) >= groups_.size()) {
            throw std::out_of_range("Group index out of range");
        }

        const auto& opt = groups_[group_id];
        if (!opt.has_value()) {
            throw std::runtime_error("Group not matched");
        }
        return *opt;
    }

    // 获取分组位置
    std::pair<size_t, size_t> span(const int group_id = 0) const {
        if (group_id < 0 || static_cast<size_t>(group_id) >= spans_.size()) {
            throw std::out_of_range("Group index out of range");
        }
        return spans_[group_id];
    }

    // 获取分组在原始字符串中的开始位置
    size_t start(const int group_id = 0) const {
        return span(group_id).first;
    }

    // 获取分组在原始字符串中的结束位置
    size_t end(const int group_id = 0) const {
        return span(group_id).second;
    }
};

// 基础模板：搜索实现
template <size_t NUM_GROUPS>
class SearchImpl {
public:
    static MatchObject execute(const RE2& pattern, const std::string& text) {
        // 包括整个匹配在内的分组总数
        constexpr size_t total_groups = NUM_GROUPS + 1;

        // 准备存储匹配结果的容器
        RE2::Arg args[total_groups];
        re2::StringPiece pieces[total_groups];

        // 初始化参数数组
        for (size_t i = 0; i < total_groups; ++i) {
            args[i] = &pieces[i];
        }

        // 尝试匹配
        re2::StringPiece input(text);
        if (!RE2::PartialMatchN(input, pattern, args, total_groups)) {
            return MatchObject(); // 匹配失败
        }

        // 计算分组在原始字符串中的位置
        const char* text_start = text.data();

        // 构建结果对象
        std::string full_match = pieces[0].as_string();
        std::vector<std::optional<std::string>> groups;
        std::vector<std::pair<size_t, size_t>> spans;

        // 添加分组0（完整匹配）
        groups.emplace_back(full_match);
        spans.emplace_back(
            pieces[0].data() - text_start,
            pieces[0].data() - text_start + pieces[0].size()
        );

        // 添加其他分组
        for (size_t i = 1; i < total_groups; ++i) {
            if (pieces[i].data() != nullptr) {
                groups.emplace_back(pieces[i].as_string());
                spans.emplace_back(
                    pieces[i].data() - text_start,
                    pieces[i].data() - text_start + pieces[i].size()
                );
            } else {
                groups.emplace_back(std::nullopt);
                spans.emplace_back(
                    std::string::npos,
                    std::string::npos
                );
            }
        }

        return MatchObject(std::move(full_match),
                          std::move(groups),
                          std::move(spans));
    }
};

// 搜索接口（自动选择分组数量实现）
MatchObject re2_search(const RE2& pattern, const std::string& text) {
    const int group_count = pattern.NumberOfCapturingGroups();

    // 无捕获分组
    if (group_count == 0) {
        return SearchImpl<0>::execute(pattern, text);
    }
    // 单捕获分组
    if (group_count == 1) {
        return SearchImpl<1>::execute(pattern, text);
    }
    // 多捕获分组
    // 为编译器生成不同分组数的代码（1-16分组）
    switch (group_count) {
        case 2: return SearchImpl<2>::execute(pattern, text);
        case 3: return SearchImpl<3>::execute(pattern, text);
        case 4: return SearchImpl<4>::execute(pattern, text);
        case 5: return SearchImpl<5>::execute(pattern, text);
        case 6: return SearchImpl<6>::execute(pattern, text);
        case 7: return SearchImpl<7>::execute(pattern, text);
        case 8: return SearchImpl<8>::execute(pattern, text);
        case 9: return SearchImpl<9>::execute(pattern, text);
        case 10: return SearchImpl<10>::execute(pattern, text);
        case 11: return SearchImpl<11>::execute(pattern, text);
        case 12: return SearchImpl<12>::execute(pattern, text);
        case 13: return SearchImpl<13>::execute(pattern, text);
        case 14: return SearchImpl<14>::execute(pattern, text);
        case 15: return SearchImpl<15>::execute(pattern, text);
        case 16: return SearchImpl<16>::execute(pattern, text);
        default:
            throw std::runtime_error("Unsupported number of capture groups");
    }
}

/**
 *
#include <iostream>
#include <vector>

int main() {
    // 编译正则表达式
    RE2 date_pattern(R"((\d{4})-(\d{2})-(\d{2}))");
    if (!date_pattern.ok()) {
        std::cerr << "Pattern compilation failed\n";
        return 1;
    }

    const std::string text = "Start date: 2023-12-15, End date: 2024-01-20";

    // 执行搜索（类似Python的re.search()）
    MatchObject result = re2_search(date_pattern, text);

    // 检查匹配状态
    if (result) {
        // 获取完整匹配
        std::cout << "Full match: " << result.group()
                  << " at position " << result.start() << "-" << result.end() << "\n";

        // 获取分组
        for (int i = 1; i <= 3; ++i) {
            try {
                auto span = result.span(i);
                std::cout << "Group " << i << ": " << result.group(i)
                          << " at [" << span.first << ", " << span.second << ")\n";
            } catch (const std::exception& e) {
                std::cout << "Group " << i << ": Not matched\n";
            }
        }
    } else {
        std::cout << "No match found\n";
    }

    // 测试可选分组
    RE2 opt_pattern(R"((\d+)(?:-(\d+))?)");
    MatchObject opt_result = re2_search(opt_pattern, "123-");

    if (opt_result) {
        std::cout << "\nOptional group test:\n";
        std::cout << "Group 1: " << opt_result.group(1) << "\n";

        try {
            std::cout << "Group 2: " << opt_result.group(2) << "\n";
        } catch (const std::exception& e) {
            std::cout << "Group 2: " << e.what() << "\n"; // Expected error
        }

        auto span2 = opt_result.span(2);
        if (span2.first == std::string::npos) {
            std::cout << "Group 2 position: Not present\n";
        }
    }

    return 0;
}
 */

#endif //RE2_H
